/*
 * Copyright (C) 2009 CityLights Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.schizoidman.android.citylights.model;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;

import android.content.Intent;
import android.util.Log;

public abstract class TCEntityLoader implements ITCEntityProxy {

	public final static int LOADING_STATE_NOT_LOADED = 0;
    public final static int LOADING_STATE_LOADING = 1;
    public final static int LOADING_STATE_LOADED = 2;
		
	private Intent mData;
	private int mLoadingState = LOADING_STATE_NOT_LOADED;

	public TCEntityLoader(Intent intent) {
		mData = new Intent(intent);
	}
	
	/* (non-Javadoc)
	 * @see com.schizoidman.android.citylights.model.ITCEntityProxy#getData()
	 */
	public Intent getData() {
		return mData;
	}
	
	public int getLoadingState() {
		return mLoadingState;
	}
	 
    private static Map<String,DefaultHttpClient> mHttpClients = new HashMap<String, DefaultHttpClient>();
    
    private synchronized static DefaultHttpClient getThreadSafeHttpClient(String host, int port, String username, String password) {
    	String key = host+":"+port;
    	DefaultHttpClient client = mHttpClients.get(key);
    	if (client == null) {
    		HttpParams params = new BasicHttpParams();
    		HttpConnectionParams.setConnectionTimeout (params, 10000);
    		HttpConnectionParams.setSoTimeout(params, 10000);
    		SchemeRegistry defaultSchemeRegistry = new DefaultHttpClient().getConnectionManager().getSchemeRegistry();
    		client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, defaultSchemeRegistry), params);
    		client.getCredentialsProvider().setCredentials( new AuthScope(host, port),
  				  new UsernamePasswordCredentials(username, password)); 
    		mHttpClients.put(key, client);
    	}
    	return client;
    }
    
    /**
     * Performs loading JSON data from HTTP server
     * @throws ClientProtocolException
     * @throws IOException
     * @throws JSONException
     */
	public void load() throws ClientProtocolException, IOException, JSONException
	{
		mLoadingState = LOADING_STATE_LOADING;
		DefaultHttpClient httpclient = getThreadSafeHttpClient(mData.getData().getHost(), mData.getData().getPort(), 
				mData.getStringExtra("username"), mData.getStringExtra("password"));

		// Prepare a request object
		HttpGet httpget = new HttpGet(mData.getDataString());
		httpget.addHeader("Accept", "application/json");

		// Execute the request
		HttpResponse response;
		response = httpclient.execute(httpget);
		// Examine the response status
		Log.i("CityLights",response.getStatusLine().toString());
		
		switch (response.getStatusLine().getStatusCode()) {
			case 401:
				throw new IOException("Bad username or password"); //TODO: Localize!!!
			case 200:
				break; // OK, continue...
			default:
				throw new IOException(response.getStatusLine().getReasonPhrase());
		}

		// Get hold of the response entity
		HttpEntity entity = response.getEntity();
		// If the response does not enclose an entity, there is no need
		// to worry about connection release

		if (entity != null) {
			// A Simple JSON Response Read
			InputStream instream = entity.getContent();
			String result= convertStreamToString(instream);
			instream.close();
			Log.i("CityLights",result);
			
			loadFromJSON(result);
		}
		mLoadingState = LOADING_STATE_LOADED;
	}
	
	protected abstract void loadFromJSON (String jsonString)  throws JSONException;
	
	private static String convertStreamToString(InputStream is) {
		/*
		 * To convert the InputStream to String we use the BufferedReader.readLine()
		 * method. We iterate until the BufferedReader return null which means
		 * there's no more data to read. Each line will appended to a StringBuilder
		 * and returned as String.
		 */
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();

		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				is.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();
	}

}
